using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using MediaBridge;
using DirectShowLib;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.IO;
using System.Windows.Media.Animation;

namespace Quad.Presentation
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>


    public partial class Window1 : System.Windows.Window
    {
        #region DirectShow
        IBaseFilter filter;
        IFilterGraph graph;
        IGraphBuilder graphBuilder;
        ICaptureGraphBuilder2 captureGB;
        
        #endregion


        bool isPlaying = false;
        bool isDark=false;

        System.Windows.Threading.DispatcherTimer dispatcherTimer;
        DateTime initial;
        bool isOverDashboard=false;
        bool isOverTraker = false;

        //string url = "MediaBridge://MyDataString";

        public Window1()
        {
            InitializeComponent();

            InitializePropertyValues();

            myMediaElement.MediaOpened += new RoutedEventHandler(Element_MediaOpened);

            #region DirectShow
            
            //MediaBridge.MediaBridgeManager.RegisterCallback(url, BridgeCallback);

            //myMediaElement.Source = new Uri(url);

            

            //this.myMediaElement.Source = new Uri(url);

            //this.myMediaElement.Play();
            
            #endregion


            initial = DateTime.Now;
            //this.dash.Visibility = Visibility.Hidden;

            #region Events 
 
            this.MouseDoubleClick += new MouseButtonEventHandler(MouseDownHandler);
            this.MouseMove+=new MouseEventHandler(MouseMoveHandler);
            this.ContentRendered += new EventHandler(Window1_ContentRendered);

            #endregion 



            dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
            dispatcherTimer.Tick += new EventHandler(WorkerThread);
            dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
            dispatcherTimer.Start();


            tracker.MouseEnter += new MouseEventHandler(tracker_MouseEnter);
            tracker.MouseLeave += new MouseEventHandler(tracker_MouseLeave);

        }

        void tracker_MouseLeave(object sender, MouseEventArgs e)
        {
            isOverTraker = false;
        }

        void tracker_MouseEnter(object sender, MouseEventArgs e)
        {
            isOverTraker = true;
        }

        void Window1_ContentRendered(object sender, EventArgs e)
        {
            Debug.Write("Render me");
        }

        void MouseDownHandler(object sender, MouseButtonEventArgs e)
        {
            if(this.WindowState == System.Windows.WindowState.Maximized)
            {
                this.WindowState = System.Windows.WindowState.Normal;
                return;
            }

            if(this.WindowState == System.Windows.WindowState.Normal)
            {
                this.WindowState= System.Windows.WindowState.Maximized;
                return;
            }
        }


        /// <summary>
        /// Stop this thread after a short while.
        /// </summary>
        private void WorkerThread(object sender, EventArgs e)
        {
            Debug.WriteLine("Worker threak execute....");

            DateTime current = DateTime.Now;

            TimeSpan spent = current - initial;

            TimeSpan ts = this.myMediaElement.Position;


            Debug.WriteLine("VALUE:" + ts.TotalMilliseconds);

            tracker.Value = ts.TotalMilliseconds;

            if (spent.TotalSeconds > 1.5f && !isOverDashboard)
            {
                //initial = DateTime.Now;

                this.dash.Visibility = Visibility.Hidden;
                //this.generic.Visibility = Visibility.Hidden;
                this.tracker.Visibility = Visibility.Hidden;

                if (this.WindowState == System.Windows.WindowState.Maximized)
                {
                    this.Cursor = Cursors.None;
                }
                Debug.WriteLine("hide dashboad");

                if (isDark)
                {
                    DoubleAnimation bck = new DoubleAnimation();

                    bck.From = 0.8;
                    bck.To = 1;
                    bck.Duration = new Duration(TimeSpan.FromMilliseconds(1000));

                    myMediaElement.BeginAnimation(MediaElement.OpacityProperty, bck);

                    isDark = false;
                }
            }

            //this.dash.IsFocused = true;
        }

        void MouseMoveHandler(object sender, MouseEventArgs e)
        {
            Debug.WriteLine("Mouse move handler/ show dashboad");

            this.initial = DateTime.Now;

            this.dash.Visibility = Visibility.Visible;
            //this.generic.Visibility = Visibility.Visible;
            this.tracker.Visibility = Visibility.Visible;

            this.dash.Opacity = 1;
            //this.generic.Opacity = 1;

            this.Cursor = Cursors.Arrow;

            if (!isDark)
            {

                DoubleAnimation bck = new DoubleAnimation();

                bck.From = 1;
                bck.To = 0.8;
                bck.Duration = new Duration(TimeSpan.FromMilliseconds(1000));

                myMediaElement.BeginAnimation(MediaElement.OpacityProperty, bck);

                isDark = true;
            }

         
        }

        void playbutton_MouseDown(Object sender, RoutedEventArgs e)
        {
            //MessageBox.Show("Mouse down");

            if (isPlaying == false)
            {
                this.myMediaElement.Play();
                isPlaying = true;
            }
            else
            {
                this.myMediaElement.Pause();
                isPlaying = false;
            }

           
        }

        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);

            if (e.RightButton == MouseButtonState.Pressed)
                return;


            this.DragMove();
        }

        void playbutton_Click(object sender, RoutedEventArgs e)
        {
            //MessageBox.Show("PLay this content");

            //stampMouseMove = DateTime.Now;
        }

        void OnOpen(object sender, RoutedEventArgs args)
        {
            ;
        }

        void openItem(object sender, RoutedEventArgs args)
        {
                      
        }

        void exitItem(object sender, RoutedEventArgs args)
        {
            Application.Current.Shutdown();
        }



        private void BridgeCallback(MediaBridgeGraphInfo GraphInfo)
        {
            int hr = 0;

            //Find a capture filter
            filter = FindCaptureDevice();

            //Convert pointer of filter graph to an object we can use
            graph = (IFilterGraph)Marshal.GetObjectForIUnknown(GraphInfo.FilterGraph);

            graphBuilder = (IGraphBuilder)graph;

            captureGB = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();

            hr = captureGB.SetFiltergraph(graphBuilder);

            //Add our capture filter to the graph
            hr = graph.AddFilter(filter, "CAPTURE");

            IBaseFilter renderer;

            //Find WPF renderer.  It's always named the same thing
            hr = graphBuilder.FindFilterByName("Enhanced Video Renderer", out renderer);

            //Render our filters outpin to the renderer
            hr = captureGB.RenderStream(PinCategory.Capture, MediaType.Video, filter, null, renderer);

            DsROTEntry entry = new DsROTEntry(graph);
        }

        /// <summary>
        /// Finds a capture filter.  From DirectShow.net sample
        /// </summary>
        /// <returns></returns>
        public IBaseFilter FindCaptureDevice()
        {
            int hr = 0;

            IEnumMoniker classEnum = null;
            IMoniker[] moniker = new IMoniker[1];

            object source = null;

            // Create the system device enumerator
            ICreateDevEnum devEnum = (ICreateDevEnum)new CreateDevEnum();

            // Create an enumerator for the video capture devices
            hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, out classEnum, 0);
            DsError.ThrowExceptionForHR(hr);

            // The device enumerator is no more needed
            Marshal.ReleaseComObject(devEnum);

            // If there are no enumerators for the requested type, then 
            // CreateClassEnumerator will succeed, but classEnum will be NULL.
            if (classEnum == null)
            {
                throw new ApplicationException("No video capture device was detected.\r\n\r\n" +
                                               "This sample requires a video capture device, such as a USB WebCam,\r\n" +
                                               "to be installed and working properly.  The sample will now close.");
            }

            // Use the first video capture device on the device list.
            // Note that if the Next() call succeeds but there are no monikers,
            // it will return 1 (S_FALSE) (which is not a failure).  Therefore, we
            // check that the return code is 0 (S_OK).

            if (classEnum.Next(moniker.Length, moniker, IntPtr.Zero) == 0)
            {
                // Bind Moniker to a filter object
                Guid iid = typeof(IBaseFilter).GUID;
                moniker[0].BindToObject(null, null, ref iid, out source);
            }
            else
            {
                throw new ApplicationException("Unable to access video capture device!");
            }

            // Release COM objects
            Marshal.ReleaseComObject(moniker[0]);
            Marshal.ReleaseComObject(classEnum);

            // An exception is thrown if cast fail
            return (IBaseFilter)source;
        }

        private void MouseOverDashboardHandler(object sender, MouseEventArgs e)
        {
            isOverDashboard = true;

            //this.dash.Visibility = Visibility.Visible;
        }

        private void MouseLeaveDashboardHandler(object sender, MouseEventArgs e)
        {
            isOverDashboard = false;

            //this.dash.Visibility = Visibility.Hidden;
        }

       
        private void clickPlay(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("PLay the stream");

            this.myMediaElement.Play();

            Debug.WriteLine("Click on play button.");

        }

        #region TODO: Check this code
        //// Play the media.
        //void OnMouseDownPlayMedia(Object sender, RoutedEventArgs e)
        //{

        //    // The Play method will begin the media if it is not currently active or 
        //    // resume media if it is paused. This has no effect if the media is
        //    // already running.
        //    myMediaElement.Play();

        //    // Initialize the MediaElement property values.
        //    InitializePropertyValues();

        //}

        //// Pause the media.
        //void OnMouseDownPauseMedia(Object sender, RoutedEventArgs e)
        //{

        //    // The Pause method pauses the media if it is currently running.
        //    // The Play method can be used to resume.
        //    myMediaElement.Pause();

        //}

        //// Stop the media.
        //void OnMouseDownStopMedia(Object sender, RoutedEventArgs e)
        //{

        //    // The Stop method stops and resets the media to be played from
        //    // the beginning.
        //    myMediaElement.Stop();

        //}

        //// Change the volume of the media.
        //private void ChangeMediaVolume(object sender, RoutedPropertyChangedEventArgs<double> args)
        //{
        //    myMediaElement.Volume = (double)volumeSlider.Value;
        //}

        // Change the speed of the media.
        //private void ChangeMediaSpeedRatio(object sender, RoutedPropertyChangedEventArgs<double> args)
        //{
        //    myMediaElement.SpeedRatio = (double)speedRatioSlider.Value;
        //}

        // When the media opens, initialize the "Seek To" slider maximum value
        // to the total number of miliseconds in the length of the media clip.
        private void Element_MediaOpened(object sender, EventArgs e)
        {
            tracker.Maximum = myMediaElement.NaturalDuration.TimeSpan.TotalMilliseconds;
        }

        //// When the media playback is finished. Stop() the media to seek to media start.
        //private void Element_MediaEnded(object sender, EventArgs e)
        //{
        //    myMediaElement.Stop();
        //}

        // Jump to different parts of the media (seek to). 
        private void SeekToMediaPosition(object sender, RoutedPropertyChangedEventArgs<double> args)
        {

            Debug.WriteLine("Seek to media position.");

            int SliderValue = (int)tracker.Value;

            // Overloaded constructor takes the arguments days, hours, minutes, seconds, miniseconds.
            // Create a TimeSpan with miliseconds equal to the slider value.
            TimeSpan ts = new TimeSpan(0, 0, 0, 0, SliderValue);
            myMediaElement.Position = ts;
        }

        private void tracker_ValueChanged(object sender, RoutedEventArgs e)
        {
            if (isOverTraker)
            {

                Debug.WriteLine("Seek to media position.");

                int SliderValue = (int)tracker.Value;

                // Overloaded constructor takes the arguments days, hours, minutes, seconds, miniseconds.
                // Create a TimeSpan with miliseconds equal to the slider value.
                TimeSpan ts = new TimeSpan(0, 0, 0, 0, SliderValue);
                myMediaElement.Position = ts;
            }
        }

        void InitializePropertyValues()
        {
            // Set the media's starting Volume and SpeedRatio to the current value of the
            // their respective slider controls.
            //myMediaElement.Volume = (double)volumeSlider.Value;
            //myMediaElement.SpeedRatio = (double)speedRatioSlider.Value;
        }

        #endregion
    }
}